import {
    BrowserType,
    ConfigObj,
    configStoreKey, ImportBookmarkType,
    initBrowserError, Language,
    Message,
    MsgType, onedrive, PageState, popupPageStatStoreKey,
    SyncMethod, SyncServiceSettingObj, UrlOpenType
} from "@/utils/constants";
import AlarmCreateInfo = chrome.alarms.AlarmCreateInfo;
import {arrayRemoveItem, overwriteConfig, parsePageStateBookmark} from "@/utils/utils";
import {BrowserDriver} from "@/utils/browser/browserDriver";
import {
    Bookmark,
    BookmarkObj, cleanupBookmarks, delBookmark, delBookmarks,
    diffBookmarks,
    dumpBookmarksJSON,
    loadBookmarksJSON,
    mergeBookmarks
} from "@/utils/bookmarkUtils";
import {
    AzureFileInfo,
    azureOAuthRoute,
    createAzureLoginURL, downloadAzureFileByPath, getAzureFileInfoByPath,
    getAzureRootFolderUrl,
    parseAzureLoginResponse, uploadAzureFile
} from "@/utils/cloudService/azure";

console.log("background.ts");

const cronTaskSuffix = "-CronTask";
const cronTaskArray: string[] = [];

const RefreshTokenTime = 30;

const CronBackupBookmarkFileName = "bookmark.cron.backup.json"
const CronBackupBookmarkFilePath = `/${CronBackupBookmarkFileName}`

const browserDriver: BrowserDriver = new BrowserDriver();
if (
    !browserDriver.restoreStorageToObject || !browserDriver.ssoAuthLogin || !browserDriver.storeObjectToStorage ||
    !browserDriver.findBookmarkPath || !browserDriver.getBookmarkTree
) {
    throw initBrowserError;
}
const restoreStorageToObject: Function = browserDriver.restoreStorageToObject;
const ssoAuthLogin = browserDriver.ssoAuthLogin;
const storeObjectToStorage: Function = browserDriver.storeObjectToStorage;
const findBookmarkPath: Function = browserDriver.findBookmarkPath;
const getBookmarkTree: Function = browserDriver.getBookmarkTree;

let result = restoreStorageToObject(configStoreKey);
let config: ConfigObj = {
    browserType: BrowserType.chrome,
    importBookmarkType: ImportBookmarkType.default,
    isCollapsedWhenBookmarkTreeNullSearch: false,
    isShowAffix: false,
    isStoreBookmarkExpandStatus: false,
    language: Language.default,
    urlOpenType: UrlOpenType.default,
    watchBookmarkChange: true,
}
if (result) {
    if (result instanceof Promise) {
        result.then((configJson) => {
            if (!configJson) {
                return;
            }
            config = JSON.parse(configJson);
            onStartup();
        })
    }
    else {
        config = JSON.parse(result);
        onStartup();
    }
}


const historyBookmarkRecord: Record<string, Bookmark[]> = {
    [onedrive]: [],
}
let currentBookmarks: Bookmark[] = [];
let pageState: PageState = {
    bookmark: [],
    filterText: "",
    tree: [],
    defaultExpandedKeys: [],
};


/**
 *
 */
async function getCurrentBookmarks() {
    let result: PageState | Promise<PageState> = restoreStorageToObject(popupPageStatStoreKey);
    if (result instanceof Promise) {
        result = await result;
    }
    pageState = result;
    currentBookmarks = parsePageStateBookmark(result);
    console.log("getCurrentBookmarks currentBookmarks", currentBookmarks);
}


async function refreshConfig() {
    let result = restoreStorageToObject(configStoreKey);
    // if (result) {
    //     if (result instanceof Promise) {
    //         result.then((configJson) => {
    //             if (!configJson) {
    //                 return;
    //             }
    //             config = JSON.parse(configJson);
    //         })
    //     }
    //     else {
    //         config = JSON.parse(result);
    //     }
    // }
    if (result instanceof Promise) {
        // console.log("refreshConfig result", result);
        result = await result;
        // console.log("refreshConfig result", result);
    }
    if (!result) {
        return
    }
    let configJson = result;
    let newConfig = JSON.parse(configJson);
    overwriteConfig(config, newConfig);
    return
}


/**
 * 保存配置
 */
function saveConfig() {
    let json = JSON.stringify(config);
    storeObjectToStorage(configStoreKey, json);
    // console.log("saveConfig", json);
}


/**
 * 获取定时任务名字
 * @param serviceName
 */
function getCronTaskName(serviceName: string): string {
    return `${serviceName}${cronTaskSuffix}`;
}


const OneDriveCronRefreshTokenTaskName: string = "OneDriveRefreshToken";


/**
 * 检查定时任务是否存在
 * @param taskName
 */
function checkCronTaskExist(taskName: string): Promise<boolean> {
    return new Promise((resolve, reject) => {
        chrome.alarms.get(taskName, (alarm) => {
            if (chrome.runtime.lastError) {
                reject(chrome.runtime.lastError);
            } else {
                resolve(alarm!== undefined);
            }
        });
    });
}


/**
 * 创建定时任务
 * @param serviceName
 * @param cronSyncTime 分钟数
 */
function createCronTask(serviceName: string, cronSyncTime: number | null | undefined) {
    if (!cronSyncTime) {
        return
    }
    const cronTaskName = getCronTaskName(serviceName);
    const cronTask: AlarmCreateInfo = {
        periodInMinutes: cronSyncTime,
    }
    chrome.alarms.create(cronTaskName, cronTask).then(r => {
        console.log("创建定时任务 r", r);
    });
    cronTaskArray.push(cronTaskName);
}


/**
 * 删除定时任务
 * @param serviceName
 */
function deleteCronTask(serviceName: string) {
    const cronTaskName = getCronTaskName(serviceName);

    // checkCronTaskExist(cronTaskName).then(flag => {
    //     if (flag) {
    //         chrome.alarms.clear(cronTaskName).then(r => {
    //             console.log("删除定时任务 r", r);
    //         });
    //         arrayRemoveItem(cronTaskArray, cronTaskName);
    //     }
    // });
    if (!cronTaskArray.includes(cronTaskName)) {
        return
    }
    chrome.alarms.clear(cronTaskName).then(r => {
        console.log("删除定时任务 r", r);
    });
    arrayRemoveItem(cronTaskArray, cronTaskName);
}


/**
 * 取消所有定时任务
 */
function clearCronTask() {
    chrome.alarms.clearAll().then(r => {
        console.log("取消所有定时任务 r", r);
    });
}


/**
 * 启动后台进程时的操作
 */
function onStartup() {
    console.log("onStartup");
    getCurrentBookmarks().then(r => {});
    let syncServiceSettingMap: Record<string, SyncServiceSettingObj> | undefined = config.syncServiceSettingMap;
    if (!syncServiceSettingMap) {
        console.log("onStartup 退出");
        return
    }
    for (const [serviceName, syncServiceSetting] of Object.entries(syncServiceSettingMap)) {
        if (syncServiceSetting.syncMethod === SyncMethod.cron) {
            if (syncServiceSetting.enable) {
                createCronTask(serviceName, syncServiceSetting.cronSyncTime);
            }
        }
        else if (syncServiceSetting.syncMethod === SyncMethod.sync) {
            // todo 创建实时同步任务
        }
    }
    // todo 刷新token方法
    console.log("启动后台进程时的操作 刷新token方法");
    oneDriveRefreshTokenTask().then(r => {});
    createCronTask(OneDriveCronRefreshTokenTaskName, RefreshTokenTime);
}


/**
 * 更新同步方式
 * @param data
 */
function updateSyncMethod(data: {
    serviceName: string,
    syncMethod: SyncMethod,
    cronSyncTime: number | null,
}) {
    console.log("updateSyncMethod data", data);
    if (data.syncMethod === SyncMethod.cron) {
        // todo 如果实时同步任务存在，则删除实时同步任务
        createCronTask(data.serviceName, data.cronSyncTime);
    }
    else if (data.syncMethod === SyncMethod.sync) {
        // todo 创建实时同步任务
        deleteCronTask(data.serviceName);
    }
    else if (data.syncMethod === SyncMethod.none) {
        // todo 删除实时同步任务
        deleteCronTask(data.serviceName);
    }
}


/**
 * todo
 */
function stopSyncService() {

}


/**
 * 更新定时时间
 */
function updateCronTime(data: {
    serviceName: string,
    cronSyncTime: number | null,
}) {
    console.log("updateCronTime data", data);
    createCronTask(data.serviceName, data.cronSyncTime);
}


/**
 * 消息类型对应的方法
 */
const MsgTypeMethodMapper: Record<string, Function> = {
    [MsgType.updateSyncMethod]: updateSyncMethod,
    [MsgType.stopSyncService]: stopSyncService,
    [MsgType.updateCronTime]: updateCronTime,
}


/**
 * oneDrive的定时任务
 */
function oneDriveCronTask() {
    console.log("oneDriveCronTask time up");
    let bookmarks = currentBookmarks;
    if (!bookmarks) {
        return false;
    }
    let addPathSet: Record<string, Bookmark> = {};
    let delPathSet: Record<string, Bookmark> = {};
    if (!!historyBookmarkRecord[onedrive]) {
        let historyBookmark = historyBookmarkRecord[onedrive];
        const diffResult = diffBookmarks(bookmarks, historyBookmark);
        addPathSet = diffResult.mainAddPathSet;
        delPathSet = diffResult.mainDelPathSet;
    }
    const syncServiceSetting = config.syncServiceSettingMap?.[onedrive];
    if (!syncServiceSetting || !syncServiceSetting.token) {
        return false;
    }
    const accessToken: string = syncServiceSetting.token;
    downloadAzureFileByPath(CronBackupBookmarkFilePath, accessToken).then((bookmarksObj: BookmarkObj | string | null | undefined) => {
        if (typeof bookmarksObj === "string") {
            // console.log("oneDriveCronTask bookmarksObj string", bookmarksObj);
            bookmarksObj = JSON.parse(bookmarksObj) as BookmarkObj;
        }
        // console.log("bookmarksObj", bookmarksObj);
        if (!bookmarksObj?.children?.length || !bookmarksObj?.children[0]?.children) {
            // console.log("处理定时任务备份书签 bookmarksObj为空");
            const bookmarksJSON = dumpBookmarksJSON(bookmarks);
            uploadAzureFile(bookmarksJSON, CronBackupBookmarkFilePath, accessToken).then(r => {});
            return true;
        }
        // console.log("oneDriveCronTask bookmarksObj", bookmarksObj);
        const backupBookmark = Bookmark.fromObject(bookmarksObj);
        // console.log("oneDriveCronTask backupBookmark", backupBookmark);
        const backupBookmarks: Bookmark[] = backupBookmark.children[0].children;
        bookmarks = mergeBookmarks(bookmarks, backupBookmarks);
        // console.log("合并远端后的bookmarks", bookmarks);
        if (delPathSet) {
            delBookmarks(delPathSet, Object.keys(delPathSet));
        }
        // console.log("删除待删除的bookmarks后", bookmarks);
        if (!bookmarks.length) {
            // console.log("处理定时任务备份书签 bookmarks长度为空");
            historyBookmarkRecord[onedrive] = bookmarks;
            return false;
        }
        const bookmarksJSON = dumpBookmarksJSON(bookmarks);
        // console.log("oneDriveCronTask currentBookmarks", currentBookmarks);
        // console.log("处理定时任务备份书签 准备上传 bookmarksJSON", bookmarksJSON);
        uploadAzureFile(bookmarksJSON, CronBackupBookmarkFilePath, accessToken).then(r => {
            historyBookmarkRecord[onedrive] = bookmarks;
            currentBookmarks = bookmarks;
            pageState.bookmark = dumpBookmarksJSON(currentBookmarks);
            storeObjectToStorage(popupPageStatStoreKey, pageState);
        });
    });
}


/**
 * oneDrive刷新令牌任务
 */
async function oneDriveRefreshTokenTask() {
    let oneDriveSetting = config.syncServiceSettingMap?.[onedrive];
    if (!oneDriveSetting || !oneDriveSetting.token) {
        console.log("oneDrive刷新令牌任务 没有token或onedrive设置，退出。");
        return ;
    }
    console.log("oneDrive刷新令牌任务 开始刷新");
    let result = ssoAuthLogin(
        createAzureLoginURL,
        azureOAuthRoute,
        parseAzureLoginResponse,
        oneDriveSetting.token
    );
    if (result instanceof Promise) {
        result = await result;
        if (!result) {
            return;
        }
    }
    else {
        if (!result) {
            return;
        }
    }
    await refreshConfig();
    oneDriveSetting = config.syncServiceSettingMap?.[onedrive];
    if (!oneDriveSetting || !oneDriveSetting.token) {
        console.log("oneDrive刷新令牌任务 没有token或onedrive设置，退出。");
        return ;
    }
    oneDriveSetting.token = result;
    saveConfig();
}


/**
 * 定时任务方法映射
 * todo 刷新任务方法
 */
const CronTaskFuncMapper = {
    [getCronTaskName(onedrive)]: oneDriveCronTask,
    [getCronTaskName(OneDriveCronRefreshTokenTaskName)]: oneDriveRefreshTokenTask,
}


// onStartup();
// chrome.runtime.onStartup.addListener( () => {
//     console.log(`onStartup`);
//     onStartup();
// });


// function removePageStateBookmark(pageState: PageState, delPath: string) {
//     let bookmarks = parsePageStateBookmark(pageState);
//     let pathSet = {};
//     const bookmarksParent = bookmarks?.[0]?.parent?? null;
//     cleanupBookmarks(bookmarks, pathSet, bookmarksParent);
//     delBookmark(pathSet, delPath);
// }


chrome.runtime.onMessage.addListener(function(data: { msg: Message }, sender, sendResponse) {
    console.log('收到内容脚本的消息：', data);
    const msg = data.msg;
    let result = "接收到消息，并执行对应方法";
    const func: Function = MsgTypeMethodMapper[msg.type];
    console.log("func", func);
    if (func) {
        func(msg.data);
    }
    else {
        result = "接收到消息，未找到对应方法";
        console.log("MsgTypeMethodMapper", MsgTypeMethodMapper);
    }
    console.log(result);
    sendResponse({"response": result});
    return true; // 保持消息通道打开，以便异步发送响应
});


chrome.alarms.onAlarm.addListener(function (alarm) {
    console.log("alarm", alarm);
    const func = CronTaskFuncMapper[alarm.name];
    if (func) {
        func();
    }
    else {
        console.log("未实现的定时任务", alarm);
    }
})


chrome.bookmarks.onCreated.addListener(async function(id, createInfo) {
    if (!config.watchBookmarkChange) {
        return
    }
    console.log('Bookmark created: ', id, createInfo);
    getBookmarkTree().then((bookmarkTree: Bookmark[]) => {
        console.log("onCreated bookmarkTree", bookmarkTree);
        mergeBookmarks(currentBookmarks, bookmarkTree);
        console.log("onCreated currentBookmarks", currentBookmarks);
        pageState.bookmark = dumpBookmarksJSON(currentBookmarks);
        console.log("onCreated pageState", pageState);
        storeObjectToStorage(popupPageStatStoreKey, pageState);
    });
});


chrome.bookmarks.onRemoved.addListener(async function(id, removeInfo) {
    if (!config.watchBookmarkChange) {
        return
    }
    console.log('Bookmark removed: ', id, removeInfo);
    // 开始从根节点遍历以找到被删除书签的路径
    // 用于存储从根到书签的路径
    let bookmarkPathStack: string[] = [];
    await findBookmarkPath(removeInfo.parentId, bookmarkPathStack);
    bookmarkPathStack.push(removeInfo.node.title);
    // todo 添加删除文件夹的名字
    const delPath = `//${bookmarkPathStack.join('/')}${removeInfo.node.url ? '' : "/"}`;
    // console.log("bookmarkPathStack", bookmarkPathStack);
    // console.log(`Bookmark with ID ${id} was removed from path: ${path}`);
    let pathSet = {};
    let  bookmarksParent = null;
    if (currentBookmarks.length && currentBookmarks[0].parent) {
        bookmarksParent = currentBookmarks[0].parent;
    }
    console.log("onRemoved bookmarksParent", bookmarksParent);
    cleanupBookmarks(currentBookmarks, pathSet, bookmarksParent);
    delBookmark(pathSet, delPath);
    pageState.bookmark = dumpBookmarksJSON(currentBookmarks);
    console.log("onRemoved pageState", pageState);
    storeObjectToStorage(popupPageStatStoreKey, pageState);
});


chrome.bookmarks.onMoved.addListener(function(id, moveInfo) {
    if (!config.watchBookmarkChange) {
        return
    }
    console.log('Bookmark moved: ', id, moveInfo);
});


chrome.bookmarks.onChanged.addListener(function(id, changeInfo) {
    if (!config.watchBookmarkChange) {
        return
    }
    console.log('Bookmark changed: ', id, changeInfo);
});


